package com.example.vote.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.example.vote.bean.*;
import com.example.vote.mapper.TItemDao;
import com.example.vote.mapper.TItemVoteDao;
import com.example.vote.service.*;
import com.example.vote.utils.SpringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 投票
 */
@RequestMapping("/vote")
@RestController
@CrossOrigin
public class VoteController {
    @Autowired
    TVoteServiceImpl voteService;
    @Autowired
    TItemDao tItemDao;
    @Autowired
    TItemVoteDao itemVoteDao;
    @Autowired
    UserVoteServiceImpl userVoteService;
    @Autowired
    ScoreContentService scoreContentService;
    @Autowired
    TItemVoteSubService itemVoteSubService;
    @Autowired
    UserServiceImpl userService;

    /**
     * 提交投票
     *
     * @param votes
     * @return
     */
    @SaCheckLogin
    @PostMapping
    public Result vote(@RequestBody FormSignVo votes) {
        if (ObjectUtils.isEmpty(votes)) {
            return Result.builder().code(500).msg("提交失败,请重新投票").build();
        }
        return voteService.vote(votes);
    }

    /**
     * 根据投票项目id 查询投票信息
     *
     * @param itemId
     * @param sort   排序方式 asc 升序 desc 降序
     * @return
     */
    @SaCheckLogin
    @GetMapping("/list")
    public Result list(String itemId, @RequestParam(defaultValue = "asc") String sort) {
        List<TVote> voteList = voteService.lambdaQuery()
                .eq(TVote::getItemId, itemId)
                .orderBy(!ObjectUtils.isEmpty(sort), "asc".equals(sort), TVote::getVoteCount)
                .list();
        HashMap<String, Object> map = new HashMap<>();
        LambdaQueryWrapper<TItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TItem::getId, itemId);
        TItem tItem = tItemDao.selectOne(wrapper);
        map.put("list", voteList);
        map.put("vote", tItem);
        return Result.success(map, "查询成功");
    }

    /**
     * 查询已投票和未投票
     *
     * @return
     */
    @SaCheckLogin
    @GetMapping("/getUserVote")
    public Result getUserVote(String itemId) {
        // 查询已投票人
        List<TItemVote> votesUserList = new LambdaQueryChainWrapper<>(itemVoteDao).eq(TItemVote::getItemId, itemId).list();
        Set<String> set = votesUserList.stream().map(TItemVote::getPhone).collect(Collectors.toSet());


        List<UserVote> list = userVoteService.lambdaQuery()
                .eq(UserVote::getItemId, itemId)
                .list();

        // 查询未投票人数
        List<UserVote> notVotesUser = list.stream()
                .filter(userVote -> !set.contains(userVote.getPhone()))
                .collect(Collectors.toList());

        // 查询已投票人
        List<UserVote> votesUser = list.stream()
                .filter(userVote -> set.contains(userVote.getPhone()))
                .collect(Collectors.toList());

        HashMap<String, Object> map = new HashMap<>();
        map.put("votesUser", votesUser);
        map.put("notVotesUser", notVotesUser);
        return Result.success(map, "查询成功");
    }

    /**
     * 查看候选人的 已投票情况
     *
     * @param itemId
     * @return
     */
    @GetMapping("/seeVote")
    @SaCheckLogin
    public Result seeVote(String itemId, @RequestParam(defaultValue = "asc") String sort) {
//        List<VoteScoreVo> values = itemVoteSubService.lambdaQuery()
//                .eq(TItemVoteSub::getItemId, itemId)
//                .list()
//                .stream()
//                .collect(Collectors.groupingBy(TItemVoteSub::getVoteId))
//                .values()
//                .stream()
//                .map((tItemVoteSubs) ->
//                        tItemVoteSubs.stream()
//                                .collect(Collectors.groupingBy(TItemVoteSub::getPhone))
//                                .values()
//                                .stream()
//                                .map(e -> e.stream().map(TItemVoteSub::getScore).reduce(Double::sum).orElse(0.0)))
//                .sorted(Comparator.comparingDouble(Double::doubleValue))
//                .map(score -> VoteScoreVo.builder().score(score).build())
//                .collect(Collectors.toList());
        // 将每个投票人的分数相加,并且按照分数排序,去除最高分和最低分,求平均值
        List<UserVote> userVoteList = userVoteService.lambdaQuery().eq(UserVote::getItemId, itemId).list();

        List<TVote> voteList = voteService.lambdaQuery().eq(TVote::getItemId, itemId).list();
        // 将voteList 转换为 id 和 voteCount 的map

        LinkedList<VoteScoreVo> voteScoreVos = new LinkedList<>();

        for (TVote vote : voteList) {
            List<TItemVoteSub> subs = itemVoteSubService.lambdaQuery()
                    .eq(TItemVoteSub::getItemId, itemId)
                    .eq(TItemVoteSub::getVoteId, vote.getId())
                    .list();
            List<Double> collect = subs.stream()
                    .collect(Collectors.groupingBy(TItemVoteSub::getPhone))
                    .values()
                    .stream()
                    .map(e -> e.stream().map(TItemVoteSub::getScore).reduce(Double::sum).orElse(0.0))
                    .sorted(Comparator.comparingDouble(Double::doubleValue))
                    .sorted()
                    .collect(Collectors.toList());

            if (collect.size() != userVoteList.size()) {
                int i = userVoteList.size() - collect.size();
                for (int j = 0; j < i; j++) {
                    collect.add(0.0);
                }
            }
            collect.sort(Comparator.comparingDouble(Double::doubleValue));
            collect.remove(0);
            collect.remove(collect.size() - 1);
            Double aDouble = collect.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
            VoteScoreVo build = VoteScoreVo.builder().score(aDouble).name(vote.getName()).phone(vote.getPhone()).build();
            voteScoreVos.add(build);
        }


//        List<VoteScoreVo> values = list.stream()
//                .collect(Collectors.groupingBy(TItemVoteSub::getVoteId))
//                .values()
//                .stream()
//                .map((tItemVoteSubs) ->
//                        tItemVoteSubs.stream()
//                                .collect(Collectors.groupingBy(TItemVoteSub::getPhone))
//                                .values()
//                                .stream()
//                                .map(e -> e.stream().map(TItemVoteSub::getScore).reduce(Double::sum).orElse(0.0)))
//                .map(score -> score.collect(Collectors.toList()))
//                .map(e -> {
//                    Collections.sort(e);
//                    e.remove(0);
//                    e.remove(e.size() - 1);
//                    return e.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
//                })
//                .sorted(Comparator.comparingDouble(Double::doubleValue))
//                .map(score -> VoteScoreVo.builder().score(score).build())
//                .collect(Collectors.toList());


        if ("desc".equals(sort)) {
            voteScoreVos.sort((o1, o2) -> o2.getScore().compareTo(o1.getScore()));
        } else {
            voteScoreVos.sort(Comparator.comparing(VoteScoreVo::getScore));
        }
        return Result.builder().code(0).total(voteScoreVos.size()).data(voteScoreVos).build();
    }


    @GetMapping("/noVoteUser")
    @SaCheckLogin
    public Result noVoteUser(String itemId) {
        List<String> strings = new LambdaQueryChainWrapper<>(itemVoteDao).eq(TItemVote::getItemId, itemId)
                .list()
                .stream()
                .map(TItemVote::getPhone)
                .collect(Collectors.toList());
        List<UserVote> voteList = userVoteService.lambdaQuery()
                .notIn(!ObjectUtils.isEmpty(strings), UserVote::getPhone, strings)
                .eq(UserVote::getItemId, itemId).list();

        return Result.builder().code(0).total(voteList.size()).data(voteList).build();
    }

    /**
     * 获取评分内容
     *
     * @param itemId
     * @return
     */
    @RequestMapping("/getScoreContent")
    public Result getScoreContent(String itemId) {
        LambdaQueryWrapper<ScoreContent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ScoreContent::getItemId, itemId);
        List<ScoreContent> contentList = scoreContentService.list(wrapper);
        return Result.success(contentList, "查询成功");
    }

    /**
     * 检查用户是否投票
     *
     * @param itemId
     * @return
     */
    @SaCheckLogin
    @GetMapping("/checkVote")
    public Result isVote(String itemId) {
        String phone = StpUtil.getLoginIdAsString();
        Long count = itemVoteDao.selectCount(new LambdaQueryWrapper<TItemVote>()
                .eq(TItemVote::getPhone, phone)
                .eq(TItemVote::getItemId, itemId));
        if (count > 0) {
            List<TItemVoteSub> list = itemVoteSubService.lambdaQuery().eq(TItemVoteSub::getPhone, phone).eq(TItemVoteSub::getItemId, itemId).list();
            Map<Integer, List<TItemVoteSub>> map = list.stream().collect(Collectors.groupingBy(TItemVoteSub::getVoteId));
            return Result.builder().data(map).code(10002).msg("已投票").build();
        } else {
            return Result.builder().code(200).msg("未投票").build();
        }
    }

    /**
     * 进入二维码投票
     *
     * @param itemId
     * @return
     */
    @SaCheckLogin
    @GetMapping("/getItemVote")
    public Result getItemVote(String itemId) {
        LocalDateTime now = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Shanghai")));
        TItem items = new LambdaQueryChainWrapper<>(tItemDao)
                .eq(TItem::getId, itemId)
                .one();

        if (ObjectUtils.isEmpty(items)) {
            return Result.builder().code(10001).msg("投票不存在").build();
        }

        // 判断用户是否已投票
        String phone = StpUtil.getLoginIdAsString();

        // 判断用户是否有权限投票
        Long aLong = userVoteService.lambdaQuery().eq(UserVote::getPhone, phone)
                .eq(UserVote::getItemId, itemId).count();
        if (aLong == 0) {
            return Result.builder().code(10004).msg("无权限投票").build();
        }
        Long count = new LambdaQueryChainWrapper<>(itemVoteDao)
                .eq(TItemVote::getPhone, phone)
                .eq(TItemVote::getItemId, itemId)
                .count();
        if (count > 0) {
            return Result.builder().code(10002).msg("已投票").build();
        }
        // 判断投票是否开始或结束
        if (now.isBefore(items.getStartTime()) || now.isAfter(items.getExpiresTime())) {
            return Result.builder().code(10003).msg("投票未开始或已结束").build();
        }
        List<TVote> vote = voteService.lambdaQuery()
                .eq(TVote::getItemId, itemId)
                .list();
        HashMap<String, Object> map = new HashMap<>();
        map.put("list", vote);
        map.put("vote", items);
        return Result.success(map, "查询成功");
    }
}
